// 游戏世界类：管理所有游戏实体
class World {
    // 构造函数：初始化游戏世界
    constructor() {
        // 存储所有实体的集合
        this.entities = new Set();
        // 用于实体分类的桶映射表
        this.buckets = new Map();

        // 创建并添加一个相机实体
        this.add(new Camera());
    }

    // 获取指定类型的实体桶
    // @param bucket: 桶的类型名称
    // @returns: 对应类型的实体集合
    bucket(bucket) {
        if (!this.buckets.has(bucket)) {
            this.buckets.set(bucket, new Set());
        }
        return this.buckets.get(bucket);
    }

    // 检查实体是否在世界中
    // @param entity: 要检查的实体
    // @returns: 布尔值，表示实体是否存在
    contains(entity) {
        return this.entities.has(entity);
    }

    // 销毁世界中的所有实体
    destroy() {
        for (const entity of this.entities) {
            entity.destroy();
        }
    }

    // 向世界添加一个或多个实体
    // @param entities: 要添加的实体列表
    add(...entities) {
        for (const entity of entities) {
            if (this.contains(entity)) return;

            // 添加到实体集合
            this.entities.add(entity);
            // 将实体添加到对应的分类桶中
            for (const bucket of entity.buckets)  {
                this.bucket(bucket).add(entity);
            }
            // 设置实体的世界引用
            entity.world = this;
        }
    }

    // 从世界中移除实体
    // @param entity: 要移除的实体
    remove(entity) {
        this.entities.delete(entity);
        // 从所有分类桶中移除该实体
        for (const bucket of entity.buckets)  {
            this.bucket(bucket).delete(entity);
        }
    }

    // 更新世界中所有实体的状态
    // @param elapsed: 距离上一帧的时间间隔
    cycle(elapsed) {
        for (const entity of this.entities) {
            entity.cycle(elapsed);
        }
    }

    // 渲染世界中的所有实体
    render() {
        // 获取相机实体
        const camera = firstItem(this.bucket('camera'));
        ctx.save();
        // 设置相机变换
        ctx.translate(CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2)
        ctx.scale(camera.zoom, camera.zoom);
        ctx.translate(-~~camera.x, -~~camera.y);

        // 渲染所有实体
        for (const entity of this.entities) {
            ctx.wrap(() => entity.render(camera));
        }

        ctx.restore();
    }

    // 等待条件满足
    // @param condition: 条件函数
    // @returns: Promise，当条件满足时解决
    waitFor(condition) {
        const conditionEntity = new Condition(condition);
        this.add(conditionEntity);
        return conditionEntity.promise();
    }
}
